<?php 
if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Captcha {
	/** 图片的宽度 */
	public $width = 180;

	/** 图片的高度 */
	public $height = 60;

	/**
     * Path for resource files (fonts, words, etc.)
     *
     * "resources" by default. For security reasons, is better move this
     * directory to another location outise the web server
     *
     */
	public $resourcesPath = 'G:\xampp\htdocs\passportV5\public';

	public $stringResource = 'ABCDEFGHJKLMNPQRTUVWXYZ2356789';

	/** Min word length (for non-dictionary random text generation) */
	public $minWordLength = 4;

	/**
     * Max word length (for non-dictionary random text generation)
     * 
     * Used for dictionary words indicating the word-length
     * for font-size modification purposes
     */
	public $maxWordLength = 4;

	/** Sessionname to store the original text */
	public $session_namespacing = 'captcha';
	

	/** Background color in RGB-array */
	public $backgroundColor = array(255, 255, 255);

	/** Foreground colors in RGB-array */
	public $colors = array(
		array(27, 78, 181), // blue
		array(22, 163, 35), // greed
		array(214, 36, 7),  // red
		array(214, 30, 20),
		array(26, 200, 40),
	);

	 /** Shadow color in RGB-array or null */
    public $shadowColor = array(226, 187,136); //array(0, 0, 0);

    /* 阴影的距离*/
    public $shadowDistance = 3;

    /*第一个字符离验证码左边的距离 */
    public $firstLetterToLeft = 25;

    /** Horizontal line through the text */
    public $lineWidth = 3;

	/**
     * Font configuration
     *
     * - font: TTF file
     * - spacing: relative pixel space between character
     * - minSize: min font size
     * - maxSize: max font size
     */
    public $fonts = array(
    	'jimuzi' => array('spacing' => -6, 'minSize' => 27, 'maxSize' => 35, 'font' => '16.ttf', 'rejust' => 0),
        'Antykwa'  => array('spacing' => -5, 'minSize' => 25, 'maxSize' => 32, 'font' => '15.TTF'),
        '10' => array('spacing' => -5, 'minSize' => 35, 'maxSize' => 35, 'font' => '10.ttf'),
        '2' => array('spacing' => -1, 'minSize' => 35, 'maxSize' => 40, 'font' => '2.ttf'),
        //'1' => array('spacing' => -3, 'minSize' => 27, 'maxSize' => 45, 'font' => '1.ttf'),
        '3' => array('spacing' => -3, 'minSize' => 28, 'maxSize' => 35, 'font' => '3.ttf'),
        '12' => array('spacing' => -3, 'minSize' => 50, 'maxSize' => 55, 'font' => '12.TTF'),
        '9' => array('spacing' => -3, 'minSize' => 27, 'maxSize' => 35, 'font' => '9.ttf'),    

    );

    /** Wave configuracion in X and Y axes */
    public $Yperiod    = 12;
    public $Yamplitude = 14;
    public $Xperiod    = 11;
    public $Xamplitude = 5;

    /* 图像是否扭曲 */
    public $isWaved = true;
    /** letter rotation clockwise 好像是字母顺时针倾斜角度*/
    public $maxRotation = 8;

	/**
     * Internal image size factor (for better image quality)
     * 1: low, 2: medium, 3: high
     */
	public $scale = 3;

	 /** 
     * Blur effect for better image quality (but slower image processing).
     * Better image results with scale=3
     */
    public $blur = true;

    /** Debug? */
    public $debug = false;
    
    /** Image format: jpeg or png */
    public $imageFormat = 'png';


    /** GD image */
    public $im;


    public function __construct($config = array()){

    }


    public function CreateImage() {
        session_start();
    	//获得一个浮点数的当前毫秒时间
    	$ini = microtime(true);

    	/** Initialization */
        $this->ImageAllocate();

        /** Text insertion */
        $text = $this->GetCaptchaText();
        $fontcfg  = $this->fonts[array_rand($this->fonts)];
        $this->WriteText($text, $fontcfg);

        $_SESSION[$this->session_namespacing]['code'] = $text;
        $_SESSION[$this->session_namespacing]['time'] = time();

        /** Transformations */
        if (!empty($this->lineWidth)) {
            $this->WriteLine();
        }
        if($this->isWaved){
        	$this->WaveImage();
        }
        
        if ($this->blur && function_exists('imagefilter')) {
            imagefilter($this->im, IMG_FILTER_GAUSSIAN_BLUR);
        }

        if ($this->blur) {
        	$this->WriteBlur();
        	$this->WriteCurve();
        }
        $this->ReduceImage();


        if ($this->debug) {
            imagestring($this->im, 1, 1, $this->height-8,
                "$text {$fontcfg['font']} ".round((microtime(true)-$ini)*1000)."ms",
                $this->GdFgColor
            );
        }


        /** Output */
        $this->WriteImage();
        $this->Cleanup();
    }

    protected function ImageAllocate() {
    	//清除原先用过的资源
    	if (!empty($this->im)) {
    		imagedestroy($this->im);
    	}
    	//为什么要乘这个比列
    	$this->im = imagecreatetruecolor($this->width*$this->scale, $this->height*$this->scale);
    	// Background color
        $this->GdBgColor = imagecolorallocate($this->im,
            $this->backgroundColor[0],
            $this->backgroundColor[1],
            $this->backgroundColor[2]
        );
        //画个矩形，为什么要用imagecreatetruecolor函数，还分配背景，直接imagecreate，再分配背景不行么？
        imagefilledrectangle($this->im, 0, 0, $this->width*$this->scale, $this->height*$this->scale, $this->GdBgColor);
        
        // Foreground color
        $color           = $this->colors[mt_rand(0, sizeof($this->colors)-1)];
        $this->GdFgColor = imagecolorallocate($this->im, $color[0], $color[1], $color[2]);

        // Shadow color
        if (!empty($this->shadowColor) && is_array($this->shadowColor) && sizeof($this->shadowColor) >= 3) {
            $this->GdShadowColor = imagecolorallocate($this->im,
                $this->shadowColor[0],
                $this->shadowColor[1],
                $this->shadowColor[2]
            );
        }

    }

    /**
     * Text generation
     *
     * @return string Text
     */
    protected function GetCaptchaText() {
    	//字符串长度不定，所以做随机
        $randomTextLength = mt_rand($this->minWordLength, $this->maxWordLength);
        //$randomTextLength = $this->maxWordLength;
        $text = "";
        for ($i = 0; $i < $randomTextLength; $i++) {
        	$text .= $this->stringResource[mt_rand(0, strlen($this->stringResource) - 1)];
        }
        return $text;
    }

    /**
     * Text insertion
     */
    protected function WriteText($text, $fontcfg = array()) {
        if (empty($fontcfg)) {
            // Select the font configuration
            $fontcfg  = $this->fonts[array_rand($this->fonts)];
        }

        // Full path of font file
        //$fontfile = $this->resourcesPath.'/fonts/'.$fontcfg['font'];
        //$fontfile = 'http://redhome-fonts.stor.sinaapp.com/captcha/1.ttf';
        $fontfile = $this->resourcesPath.'/fonts/'.$fontcfg['font'];
        //$fontfile = realpath($fontfile);

        /** Increase font-size for shortest words: 9% for each glyp missing */
        $lettersMissing = $this->maxWordLength-strlen($text);
        $fontSizefactor = 1+($lettersMissing*0.15);

        // Text generation (char by char)
        $x      = $this->firstLetterToLeft * $this->scale;
        $y      = round(($this->height*27/40)*$this->scale);
        $length = strlen($text);
        //$fontcfg['maxSize'] = ($this->width * $this->scale / $this->maxWordLength - $fontcfg['rejust'] * $this->scale) / 3.5;
        //$fontcfg['minSize'] = $fontcfg['maxSize'] - 2 * $this->scale;
        for ($i=0; $i<$length; $i++) {
        	//旋转角度
            $degree   = rand($this->maxRotation*-1, $this->maxRotation);
            $fontsize = mt_rand($fontcfg['minSize'], $fontcfg['maxSize'])*$this->scale*$fontSizefactor;
            $letter   = substr($text, $i, 1);

            if ($this->shadowColor) {
                $coords = imagettftext($this->im, $fontsize, $degree,
                    $x+$this->shadowDistance * $this->scale, $y+$this->shadowDistance * $this->scale,
                    $this->GdShadowColor, $fontfile, $letter);
            }
            $color = $this->colors[mt_rand(0, sizeof($this->colors)-1)];
        	$fontColor = imagecolorallocate($this->im, $color[0], $color[1], $color[2]);
            $coords = imagettftext($this->im, $fontsize, $degree,
                $x, $y,
                $fontColor, $fontfile, $letter);
            $x = $coords[2] + ($fontcfg['spacing']*$this->scale);
        }

        $this->textFinalX = $x;
    }

    /**
     * Horizontal line insertion
     */
    protected function WriteLine() {

        $x1 = $this->width*$this->scale*.15;
        $x2 = $this->textFinalX;
        $y1 = rand($this->height*$this->scale*.40, $this->height*$this->scale*.65);
        $y2 = rand($this->height*$this->scale*.40, $this->height*$this->scale*.65);
        $width = $this->lineWidth/2*$this->scale;

        for ($i = $width*-1; $i <= $width; $i++) {
            imageline($this->im, $x1, $y1+$i, $x2, $y2+$i, $this->GdFgColor);
        }
    }

    /**
     * Wave filter
     */
    protected function WaveImage() {
        // X-axis wave generation
        $xp = $this->scale*$this->Xperiod*rand(1,3);
        $k = rand(0, 100);
        for ($i = 0; $i < ($this->width*$this->scale); $i++) {
            imagecopy($this->im, $this->im,
                $i-1, sin($k+$i/$xp) * ($this->scale*$this->Xamplitude),
                $i, 0, 1, $this->height*$this->scale);
        }

        // Y-axis wave generation
        $k = rand(0, 100);
        $yp = $this->scale*$this->Yperiod*rand(1,2);
        for ($i = 0; $i < ($this->height*$this->scale); $i++) {
            imagecopy($this->im, $this->im,
                sin($k+$i/$yp) * ($this->scale*$this->Yamplitude), $i-1,
                0, $i, $this->width*$this->scale, 1);
        }
    }
	public function WriteBlur() {
		for ($i = 0; $i < 10; $i++) {
			$noiseColor = imagecolorallocate(   
                              $this->im,    
                              mt_rand(150,225),    
                              mt_rand(150,225),    
                              mt_rand(150,225)   
                          ); 
			for ($j = 0; $j < 5; $j++) {
				imagestring(  
                    $this->im,   
                    5 * $this->scale,    
                    mt_rand(-10, $this->width * $this->scale),    
                    mt_rand(-10,  $this->height * $this->scale),    
                    $this->stringResource[mt_rand(0, strlen($this->stringResource) - 1)], // 杂点文本为随机的字母或数字   
                    $noiseColor  
                ); 
			}
		}
	}

	public function WriteCurve() {
		$A = mt_rand(1, $this->height*$this->scale/2);                  // 振幅   
        $b = mt_rand(-$this->height*$this->scale/4, $this->height*$this->scale/4);   // Y轴方向偏移量   
        $f = mt_rand(-$this->height*$this->scale/4, $this->height*$this->scale/4);   // X轴方向偏移量   
        $T = mt_rand($this->height*$this->scale*1.5, $this->width*$this->scale*2);  // 周期   
        $w = (2* M_PI)/$T;   
                           
        $px1 = 0;  // 曲线横坐标起始位置   
        $px2 = mt_rand($this->width*$this->scale/2, $this->width*$this->scale * 0.667);  // 曲线横坐标结束位置              
        for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
        	$curveColor = imagecolorallocate(   
                              $this->im,    
                              mt_rand(150,225),    
                              mt_rand(150,225),    
                              mt_rand(150,225)   
                          );    
            if ($w!=0) {   
                $py = $A * sin($w*$px + $f)+ $b + $this->height*$this->scale/2;  // y = Asin(ωx+φ) + b   
                $i = (int) ((25 - 6)/4);   
                while ($i > 0) {    
                    imagesetpixel($this->im, $px + $i, $py + $i, $curveColor);  
					//这里画像素点比imagettftext和imagestring性能要好很多                     
                    $i--;   
                }   
            }   
        }   
           
        $A = mt_rand(1, $this->height*$this->scale/2);                  // 振幅           
        $f = mt_rand(-$this->height*$this->scale/4, $this->height*$this->scale/4);   // X轴方向偏移量   
        $T = mt_rand($this->height*$this->scale*1.5, $this->width*$this->scale*2);  // 周期   
        $w = (2* M_PI)/$T;         
        $b = $py - $A * sin($w*$px + $f) - $this->height*$this->scale/2;   
        $px1 = $px2;   
        $px2 = $this->width*$this->scale;   
        for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
        	$curveColor = imagecolorallocate(   
                              $this->im,    
                              mt_rand(150,225),    
                              mt_rand(150,225),    
                              mt_rand(150,225)   
                          );     
            if ($w!=0) {   
                $py = $A * sin($w*$px + $f)+ $b + $this->height*$this->scale/2;  // y = Asin(ωx+φ) + b   
                $i = (int) ((25 - 8)/4);   
                while ($i > 0) {            
                    imagesetpixel($this->im, $px + $i, $py + $i, $curveColor); 
					//这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出
					//的（不用while循环）性能要好很多       
                    $i--;   
                }   
            }   
        } 
	}
    /**
     * Reduce the image to the final size
     */
    protected function ReduceImage() {
        // Reduzco el tamaño de la imagen
        $imResampled = imagecreatetruecolor($this->width, $this->height);
        imagecopyresampled($imResampled, $this->im,
            0, 0, 0, 0,
            $this->width, $this->height,
            $this->width*$this->scale, $this->height*$this->scale
        );
        imagedestroy($this->im);
        $this->im = $imResampled;
    }

    /**
     * File generation
     */
    protected function WriteImage() {
        if ($this->imageFormat == 'png' && function_exists('imagepng')) {
            header("Content-type: image/png");
            imagepng($this->im);
        } else {
        	header('Pragma: no-cache'); 
            header("Content-type: image/jpeg");
            imagejpeg($this->im, null, 80);
        }
    }

    /**
     * Cleanup
     */
    protected function Cleanup() {
        imagedestroy($this->im);
    }

}

?>